// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;

namespace SnapObjects.Data
{
    /// <summary>
    ///     Represents an object used to build a SQL INSERT statement.
    ///     The SQL INSERT statement can be used to add one or more rows to a table or a view in the database.
    /// </summary>
    public class SqlInsertBuilder : SqlBuilderBase, ISqlInsertBuilder
    {
        private readonly InsertBuildStatement _statement;

        /// <summary>
        ///     Initializes a new instance of the SqlInsertBuilder class.
        /// </summary>
        /// <param name="name">(Optional) The name for this SqlInsertBuilder object.</param>
        public SqlInsertBuilder(string name = "") : this(name, new InsertBuildStatement())
        {

        }

        private SqlInsertBuilder(string name, InsertBuildStatement statement) : base(name)
        {
            _statement = statement;
        }

        /// <summary>
        ///     Gets the SQL statement type of the current object.
        /// </summary>
        public override SqlStatementType SqlType => SqlStatementType.Insert;

        internal override SqlBuildStatement Statement => _statement;

        /// <summary>
        ///     Inserts a row (by a SQL INSERT statement) and specifies the name and the schema of the table or view that will receive the data.
        /// </summary>
        /// <param name="table">The name of the table or view that will receive the data.</param>
        /// <returns>Returns the current ISqlInsertBuilder object.</returns>
        public ISqlInsertBuilder Insert(string table)
        {
            return this.Insert(table, "");
        }

        /// <summary>
        ///     Inserts a row (by a SQL INSERT statement) and specifies the name and the schema of the table or view that will receive the data.
        /// </summary>
        /// <param name="table">The name of the table or view that will receive the data.</param>
        /// <param name="schema">The schema of the table or view that will receive the data.</param>
        /// <returns>Returns the current ISqlInsertBuilder object.</returns>
        public ISqlInsertBuilder Insert(string table, string schema)
        {
            if (!_statement.Table.TryGet(out TableElement element))
            {
                _statement.Table.Add(new TableElement(schema, table, null));
            }
            else
            {
                throw new InvalidOperationException("Invalid Insert call, setting up multiple tables.");
            }

            return this;
        }

        /// <summary>
        ///     Inserts dynamic data into the column of a table. The dynamic data will be specified by a SQL parameter when the SQL is executed.
        /// </summary>
        /// <param name="columnName">The name of the column into which data will be inserted.</param>
        /// <param name="parameter">
        ///     An ISqlParameter object which represents a SQL parameter. It can be created by calling the SqlBuilder.Parameter method.
        /// </param>
        /// <returns>Returns the current ISqlInsertBuilder object.</returns>
        public ISqlInsertBuilder Column(string columnName, ISqlParameter parameter)
        {
            _statement.AddParameters(parameter);

            _statement.Columns.Add(
                new ColumnElement(columnName, null, parameter, SqlRightType.Parameter));

            return this;
        }

        /// <summary>
        ///     Specifies the value to be inserted into the column of a table.
        /// </summary>
        /// <param name="columnName">The name of the column into which data will be inserted.</param>
        /// <param name="value">The value to be inserted into the column.</param>
        /// <returns>Returns the current ISqlInsertBuilder object.</returns>
        public ISqlInsertBuilder ColumnValue(string columnName, object value)
        {
            _statement.Columns.Add(
                new ColumnElement(columnName, null, value, SqlRightType.Value));

            return this;
        }

        public override ISqlBuilder Clone()
        {
            return new SqlInsertBuilder(
                this.Name, (InsertBuildStatement)_statement.Clone());
        }
    }
}
